package list

import (
	"fmt"
)

type LNode struct {
	next, prev *LNode
	base *LList
	Value interface{}
}

type LList struct {
	root *LNode
	size int 
	locked bool
}

func NewLNode(e interface{}) *LNode {
	n := new(LNode)
	n.Value = e
	return n
}

func NewLList() *LList {
	return new(LList)
}

func (l *LList)Root() *LNode {
	return l.root
}

func (l *LList)Size() int {
	return l.size
}

func (l *LList)String() string {
	return fmt.Sprintf("LList(%p):%v",l, l.size)
}

func (l *LList)SetRoot (n *LNode) (bool, error) {
	if l.root!=nil {
		return false, nil // error not empty root
	}
	if n.prev!=nil || n.base!=nil {
		return false, nil // this is not an empty node
	}
	nodeNumber := 1
	if n.next!=nil {
		for x:=n.next; x!=nil; x=x.next {
			nodeNumber += 1
			x.base = l
		}
	}
	l.root = n
	n.base = l 
	l.size += nodeNumber
	return true, nil
}

func (n *LNode)AppendBefore(e *LNode) (bool, error) {
	l:= n.base
	if n==nil || e==nil {
		return false, nil // none of the nodes can be nil
	}
	prev := n.prev
	e.prev = prev
	if prev!=nil {
		prev.next = e
	}
	nodeNumber := 1
	last := e
	for tmp:=e.next; tmp!=nil; tmp=tmp.next {
		tmp.base = l
		nodeNumber+=1
		last = tmp
	}
	last.next = n
	n.prev = last
	e.base = l
	if l!=nil {
		l.size +=nodeNumber
	}
	return true, nil
}

func (n *LNode)AppendAfter(e *LNode)  (bool, error) {
	l := n.base
	if n==nil || e==nil {
		return false, nil // none of the nodes can be nil
	}
	next := n.next
	last := e
	nodeNumber := 1
	for tmp:=e.next; tmp!=nil; tmp=tmp.next {
		tmp.base = l
		nodeNumber+=1
		last = tmp
	}
	last.next = next
	e.prev = n
	n.next = e
	e.base = l
	if next!= nil {
		next.prev = last
	}
	if l!=nil {
		l.size +=nodeNumber
	}
	return true, nil
}

func (n *LNode)Walk(f func (*LNode, interface {}) bool, uData interface{}) bool {
	goOn := true
	for i:= n; i!=nil && goOn ; i = i.next {
		goOn = f(i, uData)
	}
	return goOn
}

func (n *LNode)String() string {
	return fmt.Sprintf("LNist(%p):%p-%v-%p", n, n.prev, n.Value, n.next)
}


func (l *LList)Remove(n *LNode) (bool, error) {
	if n==nil || l==nil {
		return false, nil // no such node
	}
	if l!=n.base {
		return false, nil // different list and node
	}
	l.size -= 1
	n.base = nil 
	if n.prev!= nil {
		n.prev.next = n.next
	}
	if n.next!=nil {
		n.next.prev = n.prev
	}
	n.prev = nil
	n.next = nil 
	return true, nil 
}